package com.adv.ems.model.vo;

import com.adv.ems.db.entity.*;
import com.adv.ems.enums.CollectPointDataTypeEnum;
import com.adv.ems.enums.SubjectTypeEnum;
import com.adv.ems.utils.EmsUtil;
import lombok.Data;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Data
public class EnergySearchCircuitDiagramTreeVO {
    private List<Node> list;

    public EnergySearchCircuitDiagramTreeVO() {
        list = new ArrayList<Node>();
    }

    @Data
    public static class Node {
        private Long nodeId;
        private Long parentId;
        private String nodeName;
        private CircuitDiagramNodeDO node;
        private List<Node> children;
        private List<Meter> meters;
        private List<Building> buildings;
        private List<Department> departments;

        public Node(CircuitDiagramNodeDO node,
                                  Collection<CircuitDiagramNodeMeterRelationDO> meterRelations,
                                  Collection<CircuitDiagramNodeEnergySubjectRelationDO> subjectRelations,
                                  Map<Long, MeterDO> meterMap,
                                  Map<Long, BuildingInfoDO> buildingInfoMap,
                                  Map<Long, DepartmentInfoDO> departmentInfoMap,
                                  Map<Long, CollectPointDO> pointMap,
                                  Map<Long, EnergyInfoDO> energyInfoMap,
                                  List<SubjectTypeEnum> excludeTypes,
                                  String acceptLanguage) {
            this.node = node;
            this.nodeId = node.getId();
            this.parentId = node.getParentId();
            this.nodeName = node.getName();
            this.children = new ArrayList<Node>();
            if (!excludeTypes.contains(SubjectTypeEnum.METER)) {
                this.meters = meterRelations
                        .stream()
                        .filter(r -> r.getDiagramNodeId().equals(node.getId()))
                        .filter(r -> meterMap.get(r.getMeterId()) != null)
                        .map(r -> new Meter(meterMap.get(r.getMeterId()), energyInfoMap, excludeTypes, pointMap))
                        .collect(Collectors.toList());
            }
            if (!excludeTypes.contains(SubjectTypeEnum.BUILDING)) {
                this.buildings = subjectRelations
                        .stream()
                        .filter(r -> r.getType().equals(SubjectTypeEnum.BUILDING.name()))
                        .filter(r -> r.getDiagramNodeId().equals(node.getId()))
                        .filter(r -> buildingInfoMap.get(r.getSubjectId()) != null)
                        .map(r -> new Building(buildingInfoMap.get(r.getSubjectId()), acceptLanguage))
                        .collect(Collectors.toList());
            }
            if (!excludeTypes.contains(SubjectTypeEnum.DEPARTMENT)) {
                this.departments = subjectRelations
                        .stream()
                        .filter(r -> r.getType().equals(SubjectTypeEnum.DEPARTMENT.name()))
                        .filter(r -> r.getDiagramNodeId().equals(node.getId()))
                        .filter(r -> departmentInfoMap.get(r.getSubjectId()) != null)
                        .map(r -> new Department(departmentInfoMap.get(r.getSubjectId()), acceptLanguage))
                        .collect(Collectors.toList());
            }
        }
    }

    @Data
    public static class Building {
        private Long buildingId;
        private String buildingName;
        public Building(BuildingInfoDO b, String acceptLanguage) {
            this.buildingId = b.getId();
            this.buildingName = EmsUtil.getNameInfo(b.getNameInfo(), acceptLanguage).getShortName();
        }
    }

    @Data
    public static class Department {
        private Long departmentId;
        private String departmentName;
        public Department(DepartmentInfoDO d, String acceptLanguage) {
            this.departmentId = d.getId();
            this.departmentName = EmsUtil.getNameInfo(d.getNameInfo(), acceptLanguage).getShortName();
        }
    }

    @Data
    public static class Meter {
        private Long meterId;
        private String meterName;
        private String energyIcon;
        private String energyCode;
        private List<Point> points;

        public Meter(MeterDO meter,
                     Map<Long, EnergyInfoDO> energyInfoMap,
                     List<SubjectTypeEnum> excludeTypes,
                     Map<Long, CollectPointDO> pointMap) {
            this.meterId = meter.getId();
            this.meterName = meter.getName();
            if (meter.getEnergyId() != null && energyInfoMap.get(meter.getEnergyId()) != null) {
                EnergyInfoDO energyInfo = energyInfoMap.get(meter.getEnergyId());
                this.energyIcon = energyInfo.getIcon();
                this.energyCode = energyInfo.getCode();
            }
            if (!excludeTypes.contains(SubjectTypeEnum.POINT)) {
                this.points = pointMap
                        .values()
                        .stream()
                        .filter(p -> meter.getId().equals(p.getMeterId()))
                        .filter(p -> CollectPointDataTypeEnum.CUMULATE.name().equals(p.getDataType()))
                        .map(Point::new)
                        .collect(Collectors.toList());
            }
        }
    }

    @Data
    public static class Point {
        private Long pointId;
        private String pointName;
        public Point(CollectPointDO p) {
            this.pointId = p.getId();
            this.pointName = p.getName();
        }
    }
}
